package com.zyzd.commontools.utils;

import android.content.Context;
import android.os.Environment;
import android.os.StatFs;
import android.support.v4.content.ContextCompat;
import android.text.TextUtils;

import com.zyzd.commontools.AppContext;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;

/**
 * Created by lzy on 2018/6/1 0001.
 * description ${文件工具类}
 */
public class FileUtils {

    /**
     * @return 内部缓存目录
     */
    public static File getCacheDir() {
        return getContext().getCacheDir();
    }

    /**
     * @return Files目录 /data/data/com.xxx.xxx/files
     */
    public static File getFilesDir() {
        return getContext().getFilesDir();
    }

    /**
     * @return 数据库目录 /data/data/com.xxx.xxx/databases
     */
    public static File getDatabaseDir() {
        return new File(ContextCompat.getDataDir(getContext()), "databases");
    }

    /**
     * @return SharedPreference目录 /data/data/com.xxx.xxx/shared_prefs
     */
    public static File getSharedPreferenceDir() {
        return new File(ContextCompat.getDataDir(getContext()), "shared_prefs");
    }

    /**
     * @return sb卡根目录
     */
    public static File getExternalStorageDirectory() {
        return Environment.getExternalStorageDirectory();
    }

    /**
     * @return 外部储存缓存目录 /mnt/sdcard/android/data/com.xxx.xxx/cache
     */
    public static File getExternalCacheDir() {
        return getContext().getExternalCacheDir();
    }

    /**
     * @param type The type of files directory to return. May be {@code null}
     *             for the root of the files directory or one of the following
     *             constants for a subdirectory:
     *             {@link android.os.Environment#DIRECTORY_MUSIC},
     *             {@link android.os.Environment#DIRECTORY_PODCASTS},
     *             {@link android.os.Environment#DIRECTORY_RINGTONES},
     *             {@link android.os.Environment#DIRECTORY_ALARMS},
     *             {@link android.os.Environment#DIRECTORY_NOTIFICATIONS},
     *             {@link android.os.Environment#DIRECTORY_PICTURES}, or
     *             {@link android.os.Environment#DIRECTORY_MOVIES}.
     * @return the absolute path to application-specific directory. May return
     * {@code null} if shared storage is not currently available
     */
    public static File getExternalFilesDir(String type) {
        return getContext().getExternalFilesDir(type);
    }

    /**
     * @param path 文件路径
     * @return 文件名
     */
    public static String getFileName(String path) {
        if (TextUtils.isEmpty(path) || !path.contains("/")) {
            return "";
        }
        return path.substring(path.lastIndexOf("/") + 1, path.length());
    }

    /**
     * @return 获取SD卡的剩余容量, 单位是Byte
     */
    public static long getSDAvailableSize() {
        if (!isSdCardAvailable()) return 0;

        // 取得sdcard文件路径
        StatFs statfs = new StatFs(getExternalStorageDirectory().getPath());
        // 获取SDCard上每个block的SIZE
        long nBlocSize = statfs.getBlockSize();
        // 获取可供程序使用的Block的数量
        long nAvailaBlock = statfs.getAvailableBlocks();
        // 计算 SDCard 剩余大小Byte
        return nAvailaBlock * nBlocSize;
    }

    /**
     * @return 当前SD卡是否可用
     */
    public static boolean isSdCardAvailable() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }


    /**
     * @param filePath 一个文件或者一个目录的文件路径
     * @return 当前文件或当前目录下的所有文件大小
     */
    public static long getFileSize(String filePath) {
        if (TextUtils.isEmpty(filePath)) return 0;
        return getFileSize(new File(filePath));
    }

    /**
     * @param file 一个文件或者一个目录
     * @return 当前文件或当前目录下的所有文件大小
     */
    public static long getFileSize(File file) {
        if (file == null) return 0;
        if (!file.exists()) return 0;
        if (file.isFile()) return file.length();

        long totalSize = 0;
        for (File subFile : file.listFiles()) {
            totalSize += getFileSize(subFile);
        }
        return totalSize;
    }

    /**
     * 删除文件或文件夹，会删除当前文件或目录
     *
     * @param filePath 指定的文件或文件夹的路径
     * @return 是否删除成功。当指定的文件路径不存在时会返回false。
     */
    public static boolean deleteFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) return false;
        return deleteFile(new File(filePath));
    }

    /**
     * 删除文件或文件夹，会删除当前文件或目录
     *
     * @param file 指定的文件或文件夹
     * @return 是否删除成功。当指定的文件路径不存在时会返回false。
     */
    public static boolean deleteFile(File file) {
        if (file == null || !file.exists()) return false;
        if (file.isFile()) return file.delete();
        for (File subFile : file.listFiles()) {
            if (!deleteFile(subFile)) return false;
        }
        return file.delete();
    }

    /**
     * 删除以特定字符串结尾的文件
     *
     * @param filePath    可以是一个文件也可以是一个文件目录
     * @param endStrs     结尾字符串,可以是一个到多个
     * @param isTraversal 是否遍历子目录
     * @return 删除文件数
     */
    public static void deleteFileByEnd(String filePath, boolean isTraversal, String... endStrs) {
        deleteFileByEnd(new File(filePath), isTraversal, endStrs);
    }

    /**
     * 删除以特定字符串结尾的文件
     *
     * @param file        可以是一个文件也可以是一个文件目录的path
     * @param endStrs     结尾字符串,可以是一个到多个
     * @param isTraversal 是否遍历子目录
     * @return 删除文件数
     */
    public static int deleteFileByEnd(File file, boolean isTraversal, String... endStrs) {
        if (file == null || !file.exists() || endStrs == null || endStrs.length == 0) return 0;
        int total = 0;
        if (file.isDirectory()) {
            for (File subFile : file.listFiles()) {
                if (subFile.isDirectory() && !isTraversal) continue;
                total += deleteFileByEnd(subFile, isTraversal, endStrs);
            }
            return total;
        }
        for (String endStr : endStrs) {
            if (TextUtils.isEmpty(endStr)) continue;
            if (file.getName().endsWith(endStr)) {
                total += (file.delete() ? 1 : 0);
            }
        }
        return total;
    }

    /**
     * 在指定目录下搜索文件
     *
     * @param file          应该传递一个目录，如果是文件会返回空集合
     * @param isTraversal   是否遍历子目录
     * @param keyword       搜索关键字
     * @param isContainsDir 是否在结果中包含符合条件的文件夹
     * @return
     */
    public static ArrayList<String> searchFile(File file, String keyword, boolean isTraversal, boolean isContainsDir) {
        ArrayList<String> results = new ArrayList<>();
        if (file == null || !file.exists() || TextUtils.isEmpty(keyword)) return results;
        if (file.isFile()) return results;
        for (File subFile : file.listFiles()) {

            if (file.getName().contains(keyword)
                    && (file.isFile() || (file.isDirectory() && isContainsDir))) {
                results.add(file.getPath());
            }

            if (subFile.isFile() || !isTraversal)
                continue;

            searchFile(subFile, keyword, true, isContainsDir);
        }
        return results;
    }

    /**
     * 在指定目录下搜索文件,会遍历子目录，不包含符合条件的文件夹
     *
     * @param file    应该传递一个目录，如果是文件会返回空集合
     * @param keyword 搜索关键字
     * @return
     */
    public static ArrayList<String> searchFile(File file, String keyword) {
        return searchFile(file, keyword, true, false);
    }

    /**
     * 格式化单位
     *
     * @param size
     * @return
     */
    public static String getFormatSize(double size) {
        double kiloByte = size / 1024;
        if (kiloByte < 1) {
            return size + "Byte";
        }

        double megaByte = kiloByte / 1024;
        if (megaByte < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "KB";
        }

        double gigaByte = megaByte / 1024;
        if (gigaByte < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "MB";
        }

        double teraBytes = gigaByte / 1024;
        if (teraBytes < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "GB";
        }
        BigDecimal result4 = new BigDecimal(teraBytes);
        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
                + "TB";
    }

    public static void close(Closeable c) {
        if (c != null) {
            try {
                c.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static Context getContext() {
        return AppContext.getContext();
    }


}
